package tw.com.hitevision.whiteboard.android.youtube.searchView.fragment;

import static tw.com.hitevision.whiteboard.android.Props.isFake4k;

import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.recyclerview.widget.RecyclerView;

import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.YouTubePlayer;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.listeners.AbstractYouTubePlayerListener;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.utils.YouTubePlayerUtils;
import com.pierfrancescosoffritti.androidyoutubeplayer.core.player.views.YouTubePlayerView;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import tw.com.hitevision.whiteboard.android.MainActivity;
import tw.com.hitevision.whiteboard.android.R;
import tw.com.hitevision.whiteboard.android.retrofit.RetrofitManager;
import tw.com.hitevision.whiteboard.android.retrofit.code.YoutubeRequestCode;
import tw.com.hitevision.whiteboard.android.retrofit.service.YoutubeAPIService;
import tw.com.hitevision.whiteboard.android.util.TextLayoutUtil;
import tw.com.hitevision.whiteboard.android.widgets.floatView.FloatingView;
import tw.com.hitevision.whiteboard.android.widgets.floatView.enums.ShowPattern;
import tw.com.hitevision.whiteboard.android.widgets.floatView.enums.SidePattern;
import tw.com.hitevision.whiteboard.android.widgets.floatView.utils.DisplayUtils;
import tw.com.hitevision.whiteboard.android.youtube.YoutubePlayerStatus;
import tw.com.hitevision.whiteboard.android.youtube.searchView.YoutubeSearchAdapter;
import tw.com.hitevision.whiteboard.android.youtube.searchView.YoutubeSearchData;

public class YoutubeSearchResultFragment extends YoutubeSearchBaseFragment {

    private final String TAG = YoutubeSearchResultFragment.class.getSimpleName();

    private static YoutubeSearchResultFragment youtubeSearchResultFragment;
    private static final String QUERY_KEY = "query_key";
    private String tempQuery;
    private YoutubeSearchAdapter youtubeSearchAdapter;
    private Disposable getSearchListDisposable, getVideoByIdDisposable, getChannelsDisposable;
    private final List<YoutubeSearchData> youtubeSearchDataList = new ArrayList<>();
    private SearchStatus currentStatus;
    private ProgressBar loadingProgressbar;
    private RecyclerView recyclerView;
    private ImageView loadingImg, noResultImg, serverErrorImg, networkErrorImg;
    private TextView loadingPrompt, noResultPrompt, serverErrorPrompt, serverErrorDescription, serverErrorTryAgain, networkErrorPrompt, networkErrorDescription, networkErrorTryAgain;

    private YoutubePlayerStatus youtubePlayerStatus;
    private int youtubeOriginWidth = 0;
    private int youtubeOriginHeight = 0;
    private float youtubeOriginX = 0f;
    private float youtubeOriginY = 0f;
    private int previousX;
    private int previousY;
    private YouTubePlayer youtubePlayer;
    private String currentVideoID;
    private boolean isVideoRunning = false;
    private int count = 1;

    public enum SearchStatus {
        PROGRESSING, SUCCESS, NO_RESULT, SERVER_ERROR, NETWORK_ERROR
    }

    public static synchronized YoutubeSearchResultFragment getInstance(String q) {
        if (youtubeSearchResultFragment == null) {
            youtubeSearchResultFragment = new YoutubeSearchResultFragment();
            Bundle args = new Bundle();
            args.putString(QUERY_KEY, q);
            youtubeSearchResultFragment.setArguments(args);
        }
        return youtubeSearchResultFragment;
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.i(TAG, "onCreateView");
        return inflater.inflate(R.layout.fragment_youtube_search_result, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        Log.i(TAG, "onViewCreated");
        loadingImg = view.findViewById(R.id.youtube_search_result_loading_image);
//        loadingProgressbar = view.findViewById(R.id.youtube_search_result_loading_progressbar);
        loadingPrompt = view.findViewById(R.id.youtube_search_result_loading_prompt);
        recyclerView = view.findViewById(R.id.youtube_search_result_recyclerView);
        noResultImg = view.findViewById(R.id.youtube_search_result_no_results_image);
        noResultPrompt = view.findViewById(R.id.youtube_search_result_no_results_prompt);
        serverErrorImg = view.findViewById(R.id.youtube_search_result_server_error_image);
        serverErrorPrompt = view.findViewById(R.id.youtube_search_result_server_error_prompt);
        serverErrorDescription = view.findViewById(R.id.youtube_search_result_server_error_description);
        serverErrorTryAgain = view.findViewById(R.id.youtube_search_result_server_error_try_again);
        networkErrorImg = view.findViewById(R.id.youtube_search_result_network_error_image);
        networkErrorPrompt = view.findViewById(R.id.youtube_search_result_network_error_prompt);
        networkErrorDescription = view.findViewById(R.id.youtube_search_result_network_error_description);
        networkErrorTryAgain = view.findViewById(R.id.youtube_search_result_network_error_try_again);
        serverErrorTryAgain.setOnClickListener(v -> getSearchVideoList(tempQuery));
        networkErrorTryAgain.setOnClickListener(v-> getSearchVideoList(tempQuery));
        if (getArguments() != null) {
            getSearchVideoList(getArguments().getString(QUERY_KEY));
        }
        youtubeSearchAdapter = new YoutubeSearchAdapter(getContext(), youtubeSearchDataList, youtubeSearchVideoListener);
        recyclerView.setWillNotDraw(false);
        recyclerView.setAdapter(youtubeSearchAdapter);
        recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState) {
                    case RecyclerView.SCROLL_STATE_IDLE:
                        Log.i(TAG, "recyclerView SCROLL_STATE_IDLE");
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:
                        Log.i(TAG, "recyclerView SCROLL_STATE_DRAGGING");
                        ((MainActivity) Objects.requireNonNull(getContext())).getYoutubeSearchView().hideKeyboard();
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:
                        Log.i(TAG, "recyclerView SCROLL_STATE_SETTLING");
                        break;
                }
            }
        });
        previousX = TextLayoutUtil.dp2px(Objects.requireNonNull(getContext()), 548);
        previousY = TextLayoutUtil.dp2px(getContext(), 168);
    }

    @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);
        Log.i(TAG, "onAttach");
    }

    private void bindingView(SearchStatus searchStatus) {
        loadingImg.setVisibility(View.GONE);
//        loadingProgressbar.setVisibility(View.GONE);
        loadingPrompt.setVisibility(View.GONE);
        recyclerView.setVisibility(View.GONE);
        noResultImg.setVisibility(View.GONE);
        noResultPrompt.setVisibility(View.GONE);
        serverErrorImg.setVisibility(View.GONE);
        serverErrorPrompt.setVisibility(View.GONE);
        serverErrorDescription.setVisibility(View.GONE);
        serverErrorTryAgain.setVisibility(View.GONE);
        networkErrorImg.setVisibility(View.GONE);
        networkErrorPrompt.setVisibility(View.GONE);
        networkErrorDescription.setVisibility(View.GONE);
        networkErrorTryAgain.setVisibility(View.GONE);
        switch (searchStatus) {
            case PROGRESSING:
                loadingImg.setVisibility(View.VISIBLE);
//                loadingProgressbar.setVisibility(View.VISIBLE);
                loadingPrompt.setVisibility(View.VISIBLE);
                break;
            case SUCCESS:
                recyclerView.setVisibility(View.VISIBLE);
                break;
            case NO_RESULT:
                noResultImg.setVisibility(View.VISIBLE);
                noResultPrompt.setVisibility(View.VISIBLE);
                break;
            case SERVER_ERROR:
                serverErrorImg.setVisibility(View.VISIBLE);
                serverErrorPrompt.setVisibility(View.VISIBLE);
                serverErrorDescription.setVisibility(View.VISIBLE);
                serverErrorTryAgain.setVisibility(View.VISIBLE);
                break;
            case NETWORK_ERROR:
                networkErrorImg.setVisibility(View.VISIBLE);
                networkErrorPrompt.setVisibility(View.VISIBLE);
                networkErrorDescription.setVisibility(View.VISIBLE);
                networkErrorTryAgain.setVisibility(View.VISIBLE);
                break;
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        Log.i(TAG, "onDestroyView");
        if (getSearchListDisposable!=null) {
            getSearchListDisposable.dispose();
        }
        if (getVideoByIdDisposable!=null) {
            getVideoByIdDisposable.dispose();
        }
        if (getChannelsDisposable!=null) {
            getChannelsDisposable.dispose();
        }
        youtubeSearchDataList.clear();
        youtubeSearchAdapter.submitList(youtubeSearchDataList);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        Log.i(TAG, "onDetach");
    }

    public void getSearchVideoList(String q) {
        Log.d(TAG, "getSearchList q:" + q);
        tempQuery = q;
        String partSnippet = "snippet";
//        String order = "viewCount";
//        String type = "video";
        int maxResults = 20;
//        String regionCode = "tw";
        String pageToken = null;
        if (getSearchListDisposable!=null) {
            if (!getSearchListDisposable.isDisposed()) {
                getSearchListDisposable.dispose();
            }
        }
        currentStatus = SearchStatus.PROGRESSING;
        bindingView(currentStatus);
        getSearchListDisposable = RetrofitManager.getInstance().getYoutubeAPIService()
                .getYoutubeSearchList(
                        YoutubeAPIService.API_KEY_AMLOGIC,
                        partSnippet,
                        null,
                        null,
                        q,
                        maxResults,
                        null,
                        pageToken)
                .subscribeOn(Schedulers.io())
                .timeout(20, TimeUnit.SECONDS)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(searchListResult -> {
                    if(searchListResult.response()!=null) {
                        switch (searchListResult.response().code()) {
                            case YoutubeRequestCode.REQUEST_SUCCESS:
                                youtubeSearchDataList.clear();
                                youtubeSearchAdapter.submitList(youtubeSearchDataList);
                                if (searchListResult.response().body() != null) {
                                    if (searchListResult.response().body().searchList.size() > 0) {
                                        for(int i = 0; i < searchListResult.response().body().searchList.size(); i++) {
                                            String videoId = searchListResult.response().body().searchList.get(i).id.videoId;
                                            if (videoId!=null) {
                                                getVideoById(videoId);
                                            }
                                        }
                                        currentStatus = SearchStatus.SUCCESS;
                                    } else {
                                        currentStatus = SearchStatus.NO_RESULT;
                                    }
                                    bindingView(currentStatus);
                                } else {
                                    throw new NullPointerException("REQUEST_NO_FOUND");
                                }
                                break;
                            case YoutubeRequestCode.REQUEST_BAD:
                                throw new NullPointerException("REQUEST_BAD");
                            case YoutubeRequestCode.REQUEST_NO_FOUND:
                                throw new NullPointerException("REQUEST_NO_FOUND");
                            default:
                                throw new NullPointerException("REQUEST_OTHER_ERROR");
                        }
                    } else {
                        throw new NullPointerException("REQUEST_OTHER_ERROR");
                    }
                }, throwable -> {
                    if (throwable.getMessage()!=null) {
                        Log.e(TAG, "getSearchVideoList throwable:" + throwable.getMessage());
                        switch (throwable.getMessage()) {
                            case "REQUEST_BAD":
                            case "REQUEST_NO_FOUND":
                                currentStatus = SearchStatus.SERVER_ERROR;
                                bindingView(currentStatus);
                                break;
                            case "REQUEST_OTHER_ERROR":
                            default:
                                currentStatus = SearchStatus.NETWORK_ERROR;
                                bindingView(currentStatus);
                                break;
                        }
                    }
                });
    }

    private void getVideoById(String id) {
        String partSnippet = "snippet";
        String partStatistics = "statistics";
        String chart = null;
        int maxResults = 1;
//        String regionCode = "tw";
        String pageToken = null;
        String fields = "kind, etag, items(kind, etag, id, snippet(publishedAt, channelId, title, description, thumbnails, channelTitle, categoryId, defaultLanguage, defaultAudioLanguage), statistics), nextPageToken, pageInfo";
        getVideoByIdDisposable = RetrofitManager.getInstance().getYoutubeAPIService()
                .getYoutubeVideoList(
                        YoutubeAPIService.API_KEY_AMLOGIC,
                        partSnippet,
                        partStatistics,
                        chart,
                        id,
                        maxResults,
                        null,
                        pageToken,
                        fields)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(videoListResult -> {
                    if(videoListResult.response()!=null) {
                        if(videoListResult.response().code() == YoutubeRequestCode.REQUEST_SUCCESS) {
                            if (videoListResult.response().body()!=null) {
//                                Video video = videoListResult.response().body().videoList.get(0);
                                String videoId = videoListResult.response().body().videoList.get(0).id;
                                String thumbURL = videoListResult.response().body().videoList.get(0).videoSnippet.thumbnails.Medium.url;
                                String title = videoListResult.response().body().videoList.get(0).videoSnippet.title;
                                String viewCount = videoListResult.response().body().videoList.get(0).videoStatistics.viewCount;
                                String publishedAt = videoListResult.response().body().videoList.get(0).videoSnippet.publishedAt;
                                String channelTitle = videoListResult.response().body().videoList.get(0).videoSnippet.channelTitle;
                                YoutubeSearchData youtubeSearchData = new YoutubeSearchData(
                                        videoId,
                                        thumbURL,
                                        title,
                                        viewCount,
                                        publishedAt,
                                        channelTitle
                                );
                                getChannelThumb(videoId, videoListResult.response().body().videoList.get(0).videoSnippet.channelId);
                                youtubeSearchDataList.add(youtubeSearchData);
                                youtubeSearchAdapter.submitList(youtubeSearchDataList);
                            }
                        } else {
                            Log.e(TAG, "code:" + videoListResult.response().code());
                        }
                    } else {
                        Log.e(TAG, "response is null");
                    }
                }, throwable -> Log.e(TAG, "getVideoById throwable:" + throwable.getMessage()));
    }

    private void getChannelThumb(String videoId, String channelId) {
        Log.i(TAG, "getChannelThumb videoId:" + videoId + ", channelId:" + channelId);
        String partSnippet = "snippet";
        int maxResults = 1;
        getChannelsDisposable = RetrofitManager.getInstance().getYoutubeAPIService()
                .getYoutubeChannelsList(
                        YoutubeAPIService.API_KEY_AMLOGIC,
                        partSnippet,
                        channelId,
                        maxResults,
                        null)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(channelsListResult -> {
                    if(channelsListResult.response()!=null) {
                        if(channelsListResult.response().code() == YoutubeRequestCode.REQUEST_SUCCESS) {
                            if(channelsListResult.response().body()!=null) {
                                for (int i=0; i<youtubeSearchDataList.size(); i++) {
                                    if (youtubeSearchDataList.get(i).getVideoId().equals(videoId)) {
                                        youtubeSearchDataList.get(i).setVideoChannelThumbURL(channelsListResult.response().body().channelsList.get(0).channelsSnippet.channelsThumbs.Default.url);
                                        break;
                                    }
                                }
                                youtubeSearchAdapter.submitList(youtubeSearchDataList);
                            } else {
                                Log.d(TAG, "getChannelThumb body is null");
                            }
                        } else {
                            Log.d(TAG, "getChannelThumb code:" + channelsListResult.response().code());
                        }
                    } else {
                        Log.d(TAG, "getChannelThumb response is null");
                    }
                }, throwable -> Log.d(TAG, "getChannelThumb throwable:" + throwable.getMessage()));
    }

    private final YoutubeSearchAdapter.YoutubeSearchVideoListener youtubeSearchVideoListener = new YoutubeSearchAdapter.YoutubeSearchVideoListener() {
        @Override
        public void OnItemClick(YoutubeSearchData youtubeSearchData) {
            Log.d(TAG, "youtubeSearchVideoListener onItemClick: " + youtubeSearchData.getVideoTitle() + ", id:" + youtubeSearchData.getVideoId());
            ((MainActivity) Objects.requireNonNull(getContext())).getYoutubeSearchView().hideKeyboard();
            String floatingViewTAG = "youtubePlayer";
            View floatingView = FloatingView.getFloatView(getActivity(), floatingViewTAG);
            if (count < 3) {
                createFloatingView(youtubeSearchData.getVideoId(),String.valueOf(System.currentTimeMillis()), previousX, previousY);
                count++;
            } else {
                ((MainActivity) Objects.requireNonNull(getContext())).showToast(getString(R.string.youtube_search_toast));
                currentVideoID = youtubeSearchData.getVideoId();
                YouTubePlayerUtils.loadOrCueVideo(youtubePlayer, getLifecycle(), youtubeSearchData.getVideoId(),0f);
            }
        }
    };

    private void changeDPI() {
        DisplayMetrics metrics = getResources().getDisplayMetrics();
        if ((float) 3.0 != metrics.density) {
            float scale = metrics.density / (float) 3.0;
            metrics.density /= scale;
            metrics.scaledDensity /= scale;
            metrics.densityDpi = (int) (metrics.densityDpi / scale);
            metrics.xdpi /= scale;
            metrics.ydpi /= scale;
            getResources().getDisplayMetrics().setTo(metrics);
        }
    }

    private void createFloatingView(String videoID, String tag, int positionX, int positionY) {
        Log.d("yqc", "createFloatingView: " + videoID);
        isVideoRunning = true;
        currentVideoID = videoID;
        FloatingView.with(Objects.requireNonNull(getActivity()))
                .setTag(tag)
                .setShowPattern(ShowPattern.CURRENT_ACTIVITY)
                .setLocation(positionX, positionY)
                .setSidePattern(SidePattern.DEFAULT)
                .setLayout(R.layout.activity_youtube_basics_web_layout, view -> {
                    ConstraintLayout rootView = view.findViewById(R.id.web_youtube_player_root_view);
                    YouTubePlayerView youTubePlayerView = view.findViewById(R.id.web_youtube_player_view);
                    ImageView exitButton = view.findViewById(R.id.web_youtube_player_custom_exit_button);
                    exitButton.setOnClickListener(v -> {
                        /*最后一个播放器窗口关闭需及时释放player资源*/
                        if (count < 3) {
                            youTubePlayerView.release();
                        }
                        if (count > 1) {
                            count--;
                        }
                        FloatingView.dismiss(getActivity(), tag);
                        FloatingView.dismissAppFloat(tag);
                    });
                    ImageView fullScreenButton = view.findViewById(R.id.web_youtube_player_full_screen_button);
                    ImageView duplicateButton = view.findViewById(R.id.web_youtube_player_duplicate);
                    duplicateButton.setOnClickListener(v-> {
                        previousX = previousX + (Math.random()>0.5?1:-1) * TextLayoutUtil.dp2px(getActivity(), 52);
                        previousY = previousY + (Math.random()>0.5?1:-1) * TextLayoutUtil.dp2px(getActivity(), 52);
                        createFloatingView(videoID, String.valueOf(System.currentTimeMillis()), previousX, previousY);
                    });
                    youtubePlayerStatus = YoutubePlayerStatus.Default;
                    fullScreenButton.setImageResource(R.drawable.ic_youtube_fullscreen);
                    duplicateButton.setEnabled(true);
                    fullScreenButton.setOnClickListener(v -> {
                        ViewGroup.LayoutParams layoutParams = rootView.getLayoutParams();
                        if (youtubePlayerStatus == YoutubePlayerStatus.Default) {
                            youtubeOriginWidth = layoutParams.width;
                            youtubeOriginHeight = layoutParams.height;
                            youtubeOriginX = FloatingView.getFloatManager(getActivity()).getFloatViewConfig(tag).getAnchorPair().getFirst();
                            youtubeOriginY = FloatingView.getFloatManager(getActivity()).getFloatViewConfig(tag).getAnchorPair().getSecond();
                            FloatingView.getFloatManager(getActivity()).getFloatView(tag).animate()
                                    .x(0)
                                    .y(0)
                                    .setDuration(0)
                                    .start();
                            youtubePlayerStatus = YoutubePlayerStatus.FullScreen;
                            fullScreenButton.setImageResource(R.drawable.ic_youtube_fullscreen_exit);
                            duplicateButton.setEnabled(false);
                            layoutParams.width = DisplayUtils.INSTANCE.getScreenWidth(getActivity());
                            layoutParams.height = DisplayUtils.INSTANCE.getScreenHeight(getActivity());
                            rootView.setLayoutParams(layoutParams);
                        } else if (youtubePlayerStatus == YoutubePlayerStatus.FullScreen) {
                            youtubePlayerStatus = YoutubePlayerStatus.Default;
                            fullScreenButton.setImageResource(R.drawable.ic_youtube_fullscreen);
                            duplicateButton.setEnabled(true);
                            layoutParams.width = youtubeOriginWidth;
                            layoutParams.height = youtubeOriginHeight;
                            rootView.setLayoutParams(layoutParams);
                            FloatingView.getFloatManager(getActivity()).getFloatView(tag).animate()
                                    .x(youtubeOriginX)
                                    .y(youtubeOriginY)
                                    .setDuration(0)
                                    .start();
                        }
                    });
                    ImageView externalButton = view.findViewById(R.id.web_youtube_player_external_button);
                    externalButton.setOnClickListener(v -> {
                        String url = "https://www.youtube.com/watch?v=" + currentVideoID;
                        Intent intent = new Intent(Intent.ACTION_VIEW);
                        intent.setData(Uri.parse(url));
                        startActivity(intent);
                    });
                    getLifecycle().addObserver(youTubePlayerView);
                    youTubePlayerView.addYouTubePlayerListener(new AbstractYouTubePlayerListener() {
                        @Override
                        public void onReady(@NonNull YouTubePlayer youTubePlayer) {
                            youtubePlayer = youTubePlayer;
                            if(isFake4k()) { changeDPI(); }
                            YouTubePlayerUtils.loadOrCueVideo(youTubePlayer, getLifecycle(), videoID,0f);
                            isVideoRunning = false;
                        }
                    });
                })
                .show();
    }
}